﻿///////////////////////////////////////////////////////////////////////////
// 文件名:     heartbeatmanage.cpp
// 描述:
// 作者:      颜磊
// 创建时间:   2024-06-08 23:44
///////////////////////////////////////////////////////////////////////////
#include "heartbeatmanage.h"
#include "sddl.h"
#include <algorithm>

SharedMemory::SharedMemory()
{
}

SharedMemory::~SharedMemory()
{
}

HANDLE SharedMemory::openSharedMemory(string name, int size)
{
    name = "Global\\" + name;
    const char *shareSSDL = "D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GA;;;IU)";
    //创建安全描述符
    SECURITY_ATTRIBUTES security;
    ZeroMemory(&security, sizeof(security));
    security.nLength = sizeof(security);
    ConvertStringSecurityDescriptorToSecurityDescriptorA(
        shareSSDL,
        SDDL_REVISION,
        &security.lpSecurityDescriptor,
        NULL);
    //以指定的安全描述符去创建共享内存
    HANDLE hMapFile = CreateFileMappingA(
        INVALID_HANDLE_VALUE, // 物理文件句柄
        &security,            // 默认安全级别
        PAGE_READWRITE,       // 可读可写
        0,                    // 高位文件大小
        size,                 // 低位文件大小
        name.c_str()          // 共享内存名称
    );
    LocalFree(security.lpSecurityDescriptor);
    return hMapFile;
}

bool SharedMemory::setSharedMemoryData(string name, char *data, int size)
{
    name = "Global\\" + name;
    // 打开共享的文件对象
    HANDLE hMapFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, NULL, name.c_str());
    if (hMapFile)
    {
        LPVOID lpBase = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        // 将共享内存数据拷贝出来
        memcpy(lpBase, data, size);
        // 解除文件映射
        UnmapViewOfFile(lpBase);
        // 关闭内存映射文件对象句柄
        CloseHandle(hMapFile);
        return true;
    }
    else
    {
        return false;
    }
}

bool SharedMemory::getSharedMemoryData(string name, char *data, int size)
{
    name = "Global\\" + name;
    memset(data, 0, size);
    // 打开共享的文件对象
    HANDLE hMapFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, NULL, name.c_str());

    if (hMapFile)
    {
        LPVOID lpBase = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        // 将共享内存数据拷贝出来
        memcpy(data, lpBase, size);
        // 解除文件映射
        UnmapViewOfFile(lpBase);
        // 关闭内存映射文件对象句柄
        CloseHandle(hMapFile);
        return true;
    }
    else
    {
        return false;
    }
}

void SharedMemory::closeSharedMemory(HANDLE hMapFile)
{
    // 关闭内存映射文件对象句柄
    if (hMapFile)
        CloseHandle(hMapFile);
}

HeartbeatManage::HeartbeatManage()
{
    isRun = false;
    char processFullName[_MAX_PATH] = {0};
    char processName[0x40] = {0};
    const size_t PROCESS_NAME_MAX_LEN = 0x40;

    // 获取进程完整路径
    if (GetModuleFileNameA(NULL, processFullName, _MAX_PATH) == 0)
    {
        // 处理获取路径失败的情况
        // 可以记录日志或设置默认名称
        strncpy_s(processName, PROCESS_NAME_MAX_LEN, "unknown_process", _TRUNCATE);
    }
    else
    {
        // 查找最后一个反斜杠
        char *tmp1 = strrchr(processFullName, '\\');
        // 查找最后一个点（扩展名分隔符）
        char *tmp2 = strrchr(processFullName, '.');

        // 处理各种路径格式情况
        if (tmp1 != nullptr)
        {
            // 从反斜杠后开始截取
            const char *nameStart = tmp1 + 1;

            // 计算要复制的长度
            size_t copyLen;
            if (tmp2 != nullptr && tmp2 > tmp1)
            {
                // 有扩展名且在反斜杠之后
                copyLen = tmp2 - nameStart;
            }
            else
            {
                // 没有扩展名或扩展名在反斜杠之前
                copyLen = strlen(nameStart);
            }

            copyLen = (copyLen < PROCESS_NAME_MAX_LEN - 1) ? copyLen : (PROCESS_NAME_MAX_LEN - 1);

            // 复制进程名
            memcpy(processName, nameStart, copyLen);
            processName[copyLen] = '\0'; // 确保字符串终止
        }
        else
        {
            // 路径中没有反斜杠，直接处理
            strncpy_s(processName, PROCESS_NAME_MAX_LEN, processFullName, _TRUNCATE);
        }
    }

    // 构造心跳头
    heartbeatHeader = std::string(processName) + "_heartbeat";
}

HeartbeatManage::~HeartbeatManage()
{
    for (std::map<string, HANDLE>::iterator it = heartbeatMap.begin(); it != heartbeatMap.end();)
    {
        sharedMemory.closeSharedMemory(it->second);
        it = heartbeatMap.erase(it); //或者mp.erase(it++)
    }
}

int HeartbeatManage::checkHeartbeat(string name, int timeoutSec)
{
    //不存则创建
    if (heartbeatMap.find(name) == heartbeatMap.end())
    {
        HANDLE hMapFile = sharedMemory.openSharedMemory(name, sizeof(HeartbeatMsg));
        heartbeatMap[name] = hMapFile;
    }
    //校验心跳信息
    HeartbeatMsg heartbeatMsg;
    if (sharedMemory.getSharedMemoryData(name, (char *)&heartbeatMsg, sizeof(HeartbeatMsg)))
    {
        //进行校验
        time_t nowTime;
        time(&nowTime);
        if (heartbeatMsg.exitFlag)
            return 2;
        if (nowTime - heartbeatMsg.timestamp < timeoutSec)
            return 1;

        return -1;
    }
    else
    {
        //异常处理
        printf("getSharedMemoryData error");
        return 0;
    }
}

void HeartbeatManage::start()
{
    if (!isRun)
    {
        isRun = true;
        beatThread = thread(&HeartbeatManage::beatRun, this);
    }
}

void HeartbeatManage::stop()
{
    if (isRun)
    {
        isRun = false;
        if (beatThread.joinable())
            beatThread.join();
    }
}

void HeartbeatManage::beat()
{
    HeartbeatMsg heartbeatMsg;
    time(&heartbeatMsg.timestamp); //获取从1970至今过了多少秒，存入time_t类型的timep
    //qDebug() << "upTime" << heartbeatHeader.c_str() << heartbeatMsg.timestamp;
    sharedMemory.setSharedMemoryData(heartbeatHeader, (char *)&heartbeatMsg, sizeof(HeartbeatMsg));
}

void HeartbeatManage::exit()
{
    HeartbeatMsg heartbeatMsg;
    time(&heartbeatMsg.timestamp); //获取从1970至今过了多少秒，存入time_t类型的timep
    heartbeatMsg.exitFlag = true;
    sharedMemory.setSharedMemoryData(heartbeatHeader, (char *)&heartbeatMsg, sizeof(HeartbeatMsg));
}

void HeartbeatManage::beatRun()
{
    isRun = true;
    while (isRun)
    {
        beat();
        Sleep(1000);
    }
}

void HeartbeatManage::setHeartbeatHeader(const string &newHeartbeatHeader)
{
    heartbeatHeader = newHeartbeatHeader;
}
